/*
 * Copyright (C) 2004 NNL Technology AB
 * Visit www.infonode.net for information about InfoNode(R) 
 * products and how to contact NNL Technology AB.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, 
 * MA 02111-1307, USA.
 */

// $Id: ViewTitleBar.java,v 1.24 2007/01/28 21:25:10 jesper Exp $
package com.supermap.desktop.ui.docking.internal;

import net.infonode.gui.ContentTitleBar;
import net.infonode.gui.DimensionProvider;
import net.infonode.gui.hover.hoverable.HoverManager;
import net.infonode.properties.gui.InternalPropertiesUtil;
import net.infonode.properties.gui.util.ComponentProperties;
import net.infonode.properties.gui.util.ShapedPanelProperties;
import net.infonode.properties.propertymap.PropertyMap;
import net.infonode.properties.propertymap.PropertyMapListener;
import net.infonode.properties.propertymap.PropertyMapTreeListener;
import net.infonode.properties.propertymap.PropertyMapWeakListenerManager;

import javax.swing.*;

import com.supermap.desktop.ui.docking.View;
import com.supermap.desktop.ui.docking.internalutil.*;
import com.supermap.desktop.ui.docking.properties.ViewTitleBarProperties;
import com.supermap.desktop.ui.docking.properties.ViewTitleBarStateProperties;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.Map;

/**
 * @author johan
 */
public class ViewTitleBar extends ContentTitleBar {
	private static final ButtonInfo[] buttonInfos = { new UndockButtonInfo(ViewTitleBarStateProperties.UNDOCK_BUTTON_PROPERTIES),
			new DockButtonInfo(ViewTitleBarStateProperties.DOCK_BUTTON_PROPERTIES),
			new MinimizeButtonInfo(ViewTitleBarStateProperties.MINIMIZE_BUTTON_PROPERTIES),
			new MaximizeButtonInfo(ViewTitleBarStateProperties.MAXIMIZE_BUTTON_PROPERTIES),
			new RestoreButtonInfo(ViewTitleBarStateProperties.RESTORE_BUTTON_PROPERTIES),
			new CloseButtonInfo(ViewTitleBarStateProperties.CLOSE_BUTTON_PROPERTIES) };

	private transient DimensionProvider minimumSizeProvider;
	private com.supermap.desktop.ui.docking.View view;
	private AbstractButton[] buttons = new AbstractButton[buttonInfos.length];
	private transient List customBarComponents;

	private transient PropertyMapTreeListener propertiesListener = new PropertyMapTreeListener() {
		@Override
		public void propertyValuesChanged(Map changes) {
			updateTitleBar(changes);
		}
	};

	private transient PropertyMapListener buttonsListener = new PropertyMapListener() {
		@Override
		public void propertyValuesChanged(PropertyMap propertyMap, Map changes) {
			updateViewButtons(null);
		}
	};

	public ViewTitleBar(View view) {
		super(view);
		this.view = view;

		PropertyMapWeakListenerManager.addWeakTreeListener(view.getViewProperties().getViewTitleBarProperties().getMap(), propertiesListener);
		PropertyMapWeakListenerManager.addWeakListener(view.getWindowProperties().getMap(), buttonsListener);

		updateTitleBar(null);
		updateTitle();
		updateViewButtons(null);

		HoverManager.getInstance().addHoverable(this);
	}

	private void updateTitle() {
		ViewTitleBarStateProperties titleProps = view.getViewProperties().getViewTitleBarProperties().getNormalProperties();
		getLabel().setText(titleProps.getTitleVisible() ? titleProps.getTitle() : null);
		getLabel().setIcon(titleProps.getIconVisible() ? titleProps.getIcon() : null);
	}

	private void updateTitleBar(Map changes) {
		updateTitle();

		JLabel label = getLabel();
		ViewTitleBarProperties titleBarProperties = view.getViewProperties().getViewTitleBarProperties();
		ShapedPanelProperties shapedProperties = titleBarProperties.getNormalProperties().getShapedPanelProperties();
		ComponentProperties componentProperties = titleBarProperties.getNormalProperties().getComponentProperties();

		updateViewButtons(changes);

		if (changes == null) {
			minimumSizeProvider = titleBarProperties.getMinimumSizeProvider();

			componentProperties.applyTo(this);

			for (int i = 0; i < buttons.length; i++)
				if (buttons[i] != null) {
					buttons[i].setForeground(componentProperties.getForegroundColor());
					buttons[i].setBackground(shapedProperties.getComponentPainter() != null ? null : componentProperties.getBackgroundColor());
				}

			label.setForeground(componentProperties.getForegroundColor());
			label.setFont(componentProperties.getFont());
			label.setIconTextGap(titleBarProperties.getNormalProperties().getIconTextGap());

			InternalPropertiesUtil.applyTo(shapedProperties, this);

			setLayoutDirection(titleBarProperties.getDirection());
			setHoverListener(titleBarProperties.getHoverListener());
			setLabelAlignment(titleBarProperties.getNormalProperties().getIconTextHorizontalAlignment());
		} else {
			// View title bar
			Map map = (Map) changes.get(titleBarProperties.getMap());
			if (map != null) {
				if (map.containsKey(ViewTitleBarProperties.MINIMUM_SIZE_PROVIDER)) {
					minimumSizeProvider = titleBarProperties.getMinimumSizeProvider();
					revalidate();
				}

				if (map.containsKey(ViewTitleBarProperties.DIRECTION))
					setLayoutDirection(titleBarProperties.getDirection());

				if (map.containsKey(ViewTitleBarProperties.HOVER_LISTENER))
					setHoverListener(titleBarProperties.getHoverListener());

			}

			// State properties
			map = (Map) changes.get(titleBarProperties.getNormalProperties().getMap());
			if (map != null) {
				if (map.containsKey(ViewTitleBarStateProperties.ICON_TEXT_GAP))
					label.setIconTextGap(titleBarProperties.getNormalProperties().getIconTextGap());

				if (map.containsKey(ViewTitleBarStateProperties.ICON_TEXT_HORIZONTAL_ALIGNMENT))
					setLabelAlignment(titleBarProperties.getNormalProperties().getIconTextHorizontalAlignment());
			}

			// Component properties
			map = (Map) changes.get(titleBarProperties.getNormalProperties().getComponentProperties().getMap());
			if (map != null) {
				componentProperties.applyTo(this);

				label.setForeground(componentProperties.getForegroundColor());
				label.setFont(componentProperties.getFont());

				for (int i = 0; i < buttons.length; i++)
					if (buttons[i] != null) {
						buttons[i].setForeground(componentProperties.getForegroundColor());
						buttons[i].setBackground(shapedProperties.getComponentPainter() != null ? null : componentProperties.getBackgroundColor());
					}
			}

			// Shaped panel properties
			map = (Map) changes.get(titleBarProperties.getNormalProperties().getShapedPanelProperties().getMap());
			if (map != null) {
				InternalPropertiesUtil.applyTo(shapedProperties, this);
			}
		}
	}

	public void updateViewButtons(Map changes) {
		InternalDockingUtil.updateButtons(buttonInfos, buttons, null, view,
				view.getViewProperties().getViewTitleBarProperties().getNormalProperties().getMap(), changes);

		if (shouldUpdateButtons())
			updateCustomBarComponents(customBarComponents);
	}

	private boolean shouldUpdateButtons() {
		JComponent[] titleComponents = getRightTitleComponents();

		if (titleComponents == null || titleComponents.length < buttons.length)
			return true;

		for (int i = 0; i < buttons.length; i++)
			if (titleComponents[titleComponents.length - i - 1] != buttons[i])
				return true;

		return false;
	}

	public void updateCustomBarComponents(List list) {
		this.customBarComponents = list;

		int size = list == null ? 0 : list.size();
		JComponent[] components = new JComponent[size + buttons.length];
		Insets[] insets = new Insets[components.length];

		if (list != null) {
			for (int i = 0; i < list.size(); i++) {
				components[i] = (JComponent) list.get(i);
				insets[i] = i == 0 ? new Insets(0, 0, 0, 0) : new Insets(0, view.getViewProperties().getViewTitleBarProperties().getNormalProperties()
						.getButtonSpacing(), 0, 0);
			}
		}

		for (int i = 0; i < buttons.length; i++) {
			int k = size + i;
			components[k] = buttons[i];
			insets[k] = k == 0 ? new Insets(0, 0, 0, 0) : new Insets(0, view.getViewProperties().getViewTitleBarProperties().getNormalProperties()
					.getButtonSpacing(), 0, 0);
		}

		setRightTitleComponents(components, insets);
	}

	public void dispose() {
		HoverManager.getInstance().removeHoverable(this);
	}

	private int pressedCount = 0;
	private boolean dragOutside = false;
	@Override
	protected void processMouseEvent(MouseEvent e) {
		if (e.getID() == MouseEvent.MOUSE_PRESSED)
			pressedCount++;

		if (e.getID() == MouseEvent.MOUSE_RELEASED) {
			pressedCount--;

			if (pressedCount <= 0)
				dragOutside = false;
		}

		super.processMouseEvent(e);
	}
	@Override
	protected void processMouseMotionEvent(MouseEvent e) {
		if (e.getID() == MouseEvent.MOUSE_DRAGGED && !dragOutside) {
			dragOutside = !contains(e.getPoint());
			if (!dragOutside)
				return;
		}

		super.processMouseMotionEvent(e);
	}
	@Override
	public Dimension getMinimumSize() {
		if (minimumSizeProvider == null)
			return super.getMinimumSize();

		Dimension d = minimumSizeProvider.getDimension(this);
		return d == null ? super.getMinimumSize() : d;
	}
	@Override
	public Dimension getPreferredSize() {
		Dimension d = minimumSizeProvider == null ? null : minimumSizeProvider.getDimension(this);

		Dimension pSize = super.getPreferredSize();
		if (d == null)
			return pSize;

		return new Dimension(Math.max(d.width, pSize.width), Math.max(d.height, pSize.height));
	}
}
